-- lua扩展
local math = math
local table = table
local string = string
local table_insert = table.insert
local table_remove = table.remove
local table_sort = table.sort
local math_random = math.random
local math_floor = math.floor
local math_randomseed = math.randomseed




----------------------------------------------------------------------
-- table扩展 
----------------------------------------------------------------------
-- 返回table大小
table.size = function(t)
	local count = 0
	for _,v in pairs(t) do
		count = count + 1
	end
	return count
end

-- 判断table是否为空
table.empty = function(t)
	return not t or not next(t)
end

-- 返回table索引列表
table.indices = function(t)
	local result = {}
	for k, v in pairs(t) do
		table_insert(result, k)
	end
end

-- 返回table值列表
table.values = function(t)
	local result = {}
	for k, v in pairs(t) do
		table_insert(result, v)
	end
end

-- 浅拷贝(只拷一层
table.clone = function(t, nometa)
	local result = {}
	if not nometa then
		setmetatable(result, getmetatable(t))
	end
	for k, v in pairs (t) do
		result[k] = v
	end
	return result
end

-- 深拷贝
table.copy = function(t, nometa)
	local result = {}

	if not nometa then
		setmetatable(result, getmetatable(t))
	end

	for k, v in pairs(t) do
		if type(v) == "table" then
			result[k] = table.copy(v)
		else
			result[k] = v
		end
	end
	return result
end

--合并
table.merge = function(dest, src)
	for k, v in pairs(src) do
		dest[k] = v
	end
end

--连接 
table.concat_list = function (tb1,tb2)
	if not tb2 then
		return
	end
	for _,v in pairs(tb2) do
		table_insert(tb1,v)
	end
end

-- 颠倒一个数组类型的table
table.reverse = function (tArray)
	if tArray == nil or #tArray == 0 then
		return {}
	end
	local tArrayReversed = {}
	local nArrCount = #tArray
	for i=1, nArrCount do
		tArrayReversed[i] = tArray[nArrCount-i+1]
	end
	return tArrayReversed
end

--table长度
table.len = function(tb)
	local length = 0
	for _,_ in pairs(tb) do
		length = length + 1
	end
	return length
end

--打乱数组
table.mix = function(arr)
	local sz = #arr
	for i = 1 , sz do
		local r = math_random(i, sz)
		local t = arr[i]
		arr[i] = arr[r]
		arr[r] = t
	end
end

--取子数组
table.sub = function(arr,star,n)
	local len = #arr
	if not n then
		n = len
	end
	if len < n or len < star then
		return {}
	end
	local tb = {}
	for i = star, n do
		table_insert(tb,arr[i])
	end
	return tb
end

--取剩余的数据(不包含star,star+n)
table.sub_rest = function(arr, star, n)
	local len = #arr
	if not n then
		n = len
	end
	local tb = {}
	for i=1, star-1 do
		table_insert(tb,arr[i])
	end
	for i=star+n,len do
		table_insert(tb,arr[i])
	end
	return tb
end

table.remove_sub = function(tb, tbSub)
	if not tbSub or not next(tbSub) then
		return
	end
	local tbRemove = {}
	local tb2 = table.copy(tb)
	for k,v in pairs(tb2) do
		for _,card in pairs(tbSub) do
			if v == card then
				table_insert(tbRemove,k)
			end
		end
	end
	local function sort(a,b)
		return a>b
	end
	table_sort(tbRemove,sort)
	for k,v in pairs(tbRemove) do
		table_remove(tb2,v)
	end
	return tb2
end

table.to_array = function(tb)
	local array = {}
	for k , v in pairs(tb) do
		table_insert(array, k)
		table_insert(array, v)
	end
	return array
end






-----------------

----------------------------------------------------------------------
-- string扩展
----------------------------------------------------------------------

-- 下标运算
do
	local mt = getmetatable("")
	local _index = mt.__index
	mt.__index = function (s, ...)
		local k = ...
		if "number" == type(k) then
			return _index.sub(s, k, k)
		else
			return _index[k]
		end
	end
end

--分割字符串
string.split = function(s, delim)
	local tb = {}
	if delim == "" then
		--把字符串分为字符数组
		for i=1, string.len(s) do
			table_insert(tb, string.sub(s, i, i))
		end
		return tb
	end
	local pattern = "[^" .. delim .. "]+"
	string.gsub(s, pattern, function(v) table_insert(tb, v) end)
	return tb
end


--去除左边空格
string.ltrim = function(s, c)
	local pattern = "^" .. (c or "%s") .. "+"
	return (string.gsub(s, pattern, ""))
end

--去除右边空格
string.rtrim = function(s, c)
	local pattern = (c or "%s") .. "+" .. "$"
	return (string.gsub(s, pattern, ""))
end

--去除左右空格
string.trim = function(s, c)
	return string.rtrim(string.ltrim(s, c), c)
end

--是否是null
string.isnull = function(s)
	return s == nil
end

--是否空字符串
string.isempty = function(s)
	return s ~= nil and string.trim(s) == ""
end

--是否为空或nil
string.isnull_or_empty = function(s)
	return s == nil or string.trim(s) == ""
end

--utf 子串
string.sub_utf_str = function(s, n)
	local dropping = string.byte(s, n+1)
	if not dropping then return s end
	if dropping >= 128 and dropping < 192 then
		return string.sub_utf_str(s, n-1)
	end
	return string.sub(s, 1, n)
end

--转为hash值
string.to_hash = function(str , max)
	if not max or max <=0 then
		max = 10000
	end
	local h = 0
	local v = 1
	local ch
	for i=1, #str do
		ch = str:byte(i)
		h = h + ch
		v = v * ch
	end
	return (h + v) % max
end

----------------------------------------------------------------------
-- math扩展
----------------------------------------------------------------------
-- 保留p位置小数
do
	local _floor = math.floor
	math.floor = function(n, p)
		if p and p ~= 0 then
			local e = 10 ^ p
			return _floor(n * e) / e
		else
			return _floor(n)
		end
	end
end

--4舍5入，保留p位置小数
math.round = function(n, p)
	local e = 10 ^ (p or 0)
	return math.floor(n * e + 0.5) / e
end

--4舍5入
math.four_five = function(n)
	if n % 1 >=0.5 then
		n = math.ceil(n)
	else
		n = math.floor(n)
	end
	return n
end

--设置随机种子
function math.randomseed(num)
	--https://www.cnblogs.com/gggzly/p/5947892.html
	if not num then
		local time = tostring(os.time())
		math.randomseed(time:reverse():sub(1, 7))
	else
		math_randomseed(num)
	end

end



----------------------------------------------------------------------
-- 
----------------------------------------------------------------------

---不会死循环的dump
local function l_dump(tab, _tostring)
	_tostring = _tostring and _tostring or tostring

	local function getkey(k, ktype)
		if ktype == 'number' then
			return '[' .. k .. ']'
		elseif ktype == 'string' then
			return '["' .. k .. '"]'
		else
			return '[' .. _tostring(k) .. ']'  --key可能是table
		end
	end

	local tinsert = table_insert
	local mmax = math.max
	local rep = string.rep
	local gsub = string.gsub
	local format = string.format

	local function dump_obj(obj, key, sp, lv, st)
		local sp = '\t'

		if type(obj) ~= 'table' then
			return sp .. (key or '') .. ' = ' .. tostring(obj) .. '\n'
		end

		local ks, vs, s= { mxl = 0 }, {}
		lv, st =  lv or 1, st or {}

		st[obj] = key or '.' --table对象列表
		key = key or ''
		for k, v in pairs(obj) do
			local ktype, vtype = type(k), type(v)
			if k ~= 'class' and k ~= '__index' and vtype ~= 'function'then
				if vtype == 'table' then
					if st[v] then --相互引用的table，直接输出
						vs[#vs + 1] = '[' .. st[v] .. ']'
						s = sp:rep(lv) .. getkey(k, ktype)
						tinsert(ks, s)
						ks.mxl = mmax(#s, ks.mxl)
					else
						st[v] = key .. '.' .. _tostring(k) --保存dump过的table，key可能也是table
						vs[#vs + 1] = dump_obj(v, st[v], sp, lv + 1, st)
						s = sp:rep(lv) .. getkey(k, ktype)
						tinsert(ks, s)
						ks.mxl = mmax(#s, ks.mxl)
					end
				else
					if vtype == 'string' then
						vs[#vs + 1] = (('%q'):format(v):gsub('\\\10','\\n'):gsub('\\r\\n', '\\n'))
					else
						vs[#vs + 1] = tostring(v)
					end
					s = sp:rep(lv) .. getkey(k, ktype)
					tinsert(ks, s)
					ks.mxl = mmax(#s, ks.mxl);
				end
			end
		end

		s = ks.mxl
		for i, v in ipairs(ks) do
			vs[i] = v .. (' '):rep(s - #v) .. ' = ' .. vs[i] .. '\n'
		end

		return '{\n' .. table.concat(vs) .. sp:rep(lv-1) .. '}'
	end

	return dump_obj(tab)
end

-- dump = l_dump   --兼容需要


---其他地方需要使用原始的tostring
sys_tostring = tostring
local _tostring = tostring
tostring = function(v)
	if type(v) == 'table' then
		return l_dump(v, _tostring)
	else
		return _tostring(v)
	end
end

